import * as THREE from "three";

// 引入轨道控制器控制器
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
// 引入动画库
import gsap from "gsap";
// 引入数据图形用户界面库
import * as dat from "dat.gui";
// 引入rgbeLoad
// DataTextureLoader
// 用于加载二进制文件格式的(rgbe, hdr, ...)的抽象类。 内部使用FileLoader来加载文件， 和创建一个新的 DataTexture.
import { RGBELoader } from "three/examples/jsm/loaders/RGBELoader.js"
// 引入物理引擎
import * as CANNON from 'cannon-es';
// 用于载入glTF 2.0资源的加载器。
// glTF（gl传输格式）是一种开放格式的规范 （open format specification）， 用于更高效地传输、加载3D内容。
// 该类文件以JSON（.gltf）格式或二进制（.glb）格式提供， 外部文件存储贴图（.jpg、.png）和额外的二进制数据（.bin）。
// 一个glTF组件可传输一个或多个场景， 包括网格、材质、贴图、蒙皮、骨架、变形目标、动画、灯光以及摄像机。
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js"

// 导入官方例子中使用的水实现 需要导入材质纹理
import { Water } from 'three/examples/jsm/objects/Water2.js';

// 用于在three.js中实现后期处理效果。该类管理了产生最终视觉效果的后期处理过程链。 
// 后期处理过程根据它们添加/插入的顺序来执行，最后一个过程会被自动渲染到屏幕上。
import {EffectComposer} from 'three/examples/jsm/postprocessing/EffectComposer';
import {RenderPass} from 'three/examples/jsm/postprocessing/RenderPass';
import {DotScreenPass} from 'three/examples/jsm/postprocessing/DotScreenPass';
import {SMAAPass} from 'three/examples/jsm/postprocessing/SMAAPass'
import {SSAARenderPass} from 'three/examples/jsm/postprocessing/SSAARenderPass'
import {GlitchPass} from 'three/examples/jsm/postprocessing/GlitchPass'
import {UnrealBloomPass} from 'three/examples/jsm/postprocessing/UnrealBloomPass'
import {ShaderPass} from 'three/examples/jsm/postprocessing/ShaderPass'
// 引入CSS 2D渲染器
import { CSS2DRenderer,CSS2DObject } from "three/examples/jsm/renderers/CSS2DRenderer.js";


// 加载纹理
// 创建纹理加载器对象
let camera, scene, renderer, labelRenderer;

const clock = new THREE.Clock();
const textureLoader = new THREE.TextureLoader();

let moon;
let chinaPosition;
let chinaLabel;
let chinaDiv;
// 实例化射线
const raycaster = new THREE.Raycaster();
init();
animate();

function init() {
  const EARTH_RADIUS = 1;
  const MOON_RADIUS = 0.27;

  camera = new THREE.PerspectiveCamera(
    45,
    window.innerWidth / window.innerHeight,
    0.1,
    200
  );
  camera.position.set(0, 5, -10);

  scene = new THREE.Scene();

  const dirLight = new THREE.DirectionalLight(0xffffff);
  dirLight.position.set(0, 0, 1);
  scene.add(dirLight);
  const light = new THREE.AmbientLight(0xffffff, 0.5); // soft white light
  scene.add(light);

  const earthGeometry = new THREE.SphereGeometry(EARTH_RADIUS, 16, 16);
  const earthMaterial = new THREE.MeshPhongMaterial({
    specular: 0x333333, // 材质的高光颜色。默认值为0x111111（深灰色）的颜色Color。
    shininess: 10, //.specular高亮的程度，越高的值越闪亮。默认值为 30。
    map: textureLoader.load("textures/planets/earth_atmos_2048.jpg"),
    specularMap: textureLoader.load("textures/planets/earth_specular_2048.jpg"),
    normalMap: textureLoader.load("textures/planets/earth_normal_2048.jpg"),
    normalScale: new THREE.Vector2(0.85, 0.85), //法线贴图对材质的影响程度。典型范围是0-1。默认值是Vector2设置为（1,1）。
  });

  const earth = new THREE.Mesh(earthGeometry, earthMaterial);
  // earth.rotation.y = Math.PI;
  scene.add(earth);

  const moonGeometry = new THREE.SphereGeometry(MOON_RADIUS, 16, 16);
  const moonMaterial = new THREE.MeshPhongMaterial({
    shininess: 5,
    map: textureLoader.load("textures/planets/moon_1024.jpg"),
  });
  moon = new THREE.Mesh(moonGeometry, moonMaterial);
  scene.add(moon);

  // 添加提示标签
  const earthDiv = document.createElement('div');
  earthDiv.className = "label";
  earthDiv.innerHTML = "地球";
  const earthLabel = new CSS2DObject(earthDiv);
  earthLabel.position.set(0,1,0);
  earth.add(earthLabel);

  const chinaDiv = document.createElement('div');
  chinaDiv.className = "label1";
  chinaDiv.innerHTML = "中国";
  chinaLabel = new CSS2DObject(chinaDiv);
  chinaLabel.position.set(-0.3,0.7,-0.9);
  earth.add(chinaLabel);
  console.log(chinaLabel)


  const moonDiv = document.createElement('div');
  moonDiv.className = "label";
  moonDiv.innerHTML = "月球";
  const moonLabel = new CSS2DObject(moonDiv);
  moonLabel.position.set(0,0.3,0); //相对于要添加到物体的位置
  moon.add(moonLabel);


  //实例化css2d的渲染器
  labelRenderer = new CSS2DRenderer();
  labelRenderer.setSize(window.innerWidth, window.innerHeight);
  document.body.appendChild(labelRenderer.domElement)
  labelRenderer.domElement.style.position = 'fixed';
  labelRenderer.domElement.style.top = '0px';
  labelRenderer.domElement.style.left = '0px';
  labelRenderer.domElement.style.zIndex = '10';



  renderer = new THREE.WebGLRenderer();
  renderer.setPixelRatio(window.devicePixelRatio);
  renderer.setSize(window.innerWidth, window.innerHeight);
  document.body.appendChild(renderer.domElement);

  const controls = new OrbitControls(camera,labelRenderer.domElement);
  controls.minDistance = 5;
  controls.maxDistance = 100;

  window.addEventListener("resize", onWindowResize);
}

function onWindowResize() {
  camera.aspect = window.innerWidth / window.innerHeight;

  camera.updateProjectionMatrix();

  renderer.setSize(window.innerWidth, window.innerHeight);
  labelRenderer.setSize(window.innerWidth, window.innerHeight);
}



function animate() {
  requestAnimationFrame(animate);

  const elapsed = clock.getElapsedTime();

  moon.position.set(Math.sin(elapsed) * 5, 0, Math.cos(elapsed) * 5);


  const chinaPosition = chinaLabel.position.clone();
  // 计算出标签跟摄像机的距离
  // .distanceTo ( v : Vector3 ) : Float
  // 计算该向量到所传入的v间的距离。
  const labelDistance = chinaPosition.distanceTo(camera.position);
  // 检测射线的碰撞
  // chinaLabel.position
  // 向量(坐标)从世界空间投影到相机的标准化设备坐标 (NDC) 空间。
  // console.log("start",chinaPosition);
  chinaPosition.project(camera);
  // console.log("project",chinaPosition);
  // .setFromCamera ( coords : Vector2, camera : Camera ) : undefined
  // coords —— 在标准化设备坐标中鼠标的二维坐标 —— X分量与Y分量应当在-1到1之间。
  // camera —— 射线所来源的摄像机。
  // 使用一个新的原点和方向来更新射线。
  raycaster.setFromCamera(chinaPosition,camera);

  // .intersectObjects ( objects : Array, recursive : Boolean, optionalTarget : Array ) : Array
  // objects —— 检测和射线相交的一组物体。
  // recursive —— 若为true，则同时也会检测所有物体的后代。否则将只会检测对象本身的相交部分。默认值为true。
  // optionalTarget —— （可选）设置结果的目标数组。如果不设置这个值，则一个新的Array会被实例化；如果设置了这个值，
  // 则在每次调用之前必须清空这个数组（例如：array.length = 0;）。

  // 检测所有在射线与这些物体之间，包括或不包括后代的相交部分。
  // 返回结果时，相交部分将按距离进行排序，最近的位于第一个），相交部分和.intersectObject所返回的格式是相同的。
  const intersects = raycaster.intersectObjects(scene.children,true)
  // console.log(intersects)
  
  // 如果没有碰撞到任何物体，那么让标签显示
  if(intersects.length == 0){
    chinaLabel.element.classList.add('visible');
    
  }else{
    // 射线投射原点和相交部分之间的距离。
    const minDistance = intersects[0].distance;
    console.log(minDistance,labelDistance)
    if(minDistance<labelDistance){
      chinaLabel.element.classList.remove('visible');
    }else{
      chinaLabel.element.classList.add('visible');
    }
  }

  // 标签渲染器渲染
  labelRenderer.render(scene,camera);

  renderer.render(scene, camera);
}

